package com.suoluo.zenadmin.controllers.portal.wx;

import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.paoding.rose.web.Invocation;
import net.paoding.rose.web.annotation.Param;
import net.paoding.rose.web.annotation.Path;
import net.paoding.rose.web.annotation.rest.Get;
import net.paoding.rose.web.annotation.rest.Post;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.suoluo.zenadmin.common.encrypt.EncryptUtil;

@Path("")
public class WXServiceController {
	private static final Log logger = LogFactory
			.getLog(WXServiceController.class);

	private static final String TOKEN = "wx_token_zentravel";

	/**
	 * 微信的接入验证 signature
	 * 微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 timestamp 时间戳
	 * nonce 随机数 echostr 随机字符串
	 * 
	 * @param inv
	 * @return
	 */
	@Get("/")
	public String get(Invocation inv, @Param("signature") String signature,
			@Param("timestamp") String timestamp, @Param("nonce") String nonce,
			@Param("echostr") String echostr) {

		if (timestamp == null || nonce == null) {
			return "@param is null";
		}
		/*
		 * 开发者通过检验signature对请求进行校验（下面有校验方式）。
		 * 若确认此次GET请求来自微信服务器，请原样返回echostr参数内容，则接入生效， 成为开发者成功，否则接入失败。
		 */
		String[] tempArray = { TOKEN, timestamp, nonce };
		Arrays.sort(tempArray);
		String joinStr = tempArray[0] + tempArray[1] + tempArray[2];
		String sha1Str = EncryptUtil.sha1(joinStr);
		if (sha1Str.equalsIgnoreCase(signature)) {
			return "@" + echostr;
		}
		return "@invalid";
	}

	@Post("/")
	public void post(Invocation inv) {
		try {
			Map<String, String> params = parseXml(inv.getRequest());
			// 消息类型
			String msgType = params.get("MsgType");
			// 事件推送
			if (msgType.equals("event")) {

				String replyResult = null;
				// 事件类型
				String eventType = params.get("Event");
				// 关注
				if (eventType.equals("subscribe")) {
					replyResult = replySubscribe(params);
				}
				// 取消关注
				else if (eventType.equals("unsubscribe")) {
					// 取消订阅后用户再收不到公众号发送的消息，因此不需要回复消息
				}
				// 自定义菜单点击事件
				else if (eventType.equals("CLICK")) {
					// 点击菜单的Key(首页，)
					// String eventKey = requestMap.get("EventKey");
					// 根据不同的key值返回不同的消息链接
					replyResult = replyMenuClick(params);
				}
				if (replyResult != null) {
					HttpServletResponse response = inv.getResponse();
					if (response.getContentType() == null) {
						response.setContentType("text/xml;charset=UTF-8");
					}
					response.getWriter().write(replyResult);
				}
			}
		} catch (Exception e) {
			logger.error("", e);
		}
	}

	private String replySubscribe(Map<String, String> params) {
		// 发送方帐号（open_id）
		String fromUserName = params.get("FromUserName");
		// 公众帐号
		String toUserName = params.get("ToUserName");
		StringBuilder replyBuf = new StringBuilder();
		replyBuf.append("<xml>");
		// ToUserName 是 接收方帐号（收到的OpenID）
		replyBuf.append(buildTextNode("ToUserName", fromUserName));

		// FromUserName 是 开发者微信号
		replyBuf.append(buildTextNode("FromUserName", toUserName));

		// CreateTime 是 消息创建时间 （整型）
		replyBuf.append(buildTextNode("CreateTime",
				String.valueOf(getCurTimeSeconds())));
		// MsgType 是 text
		replyBuf.append(buildTextNode("MsgType", "text"));
		// Content 是 回复的消息内容（换行：在content中能够换行，微信客户端就支持换行显示）
		replyBuf.append(buildTextNode("Content", "感谢您的关注"));
		replyBuf.append("</xml>");
		return replyBuf.toString();
	}

	private String replyMenuClick(Map<String, String> params) {
		// 发送方帐号（open_id）
		String fromUserName = params.get("FromUserName");
		// 公众帐号
		String toUserName = params.get("ToUserName");
		StringBuilder replyBuf = new StringBuilder();
		replyBuf.append("<xml>");
		// ToUserName 是 接收方帐号（收到的OpenID）
		replyBuf.append(buildTextNode("ToUserName", fromUserName));

		// FromUserName 是 开发者微信号
		replyBuf.append(buildTextNode("FromUserName", toUserName));
		// CreateTime 是 消息创建时间 （整型）
		replyBuf.append(buildTextNode("CreateTime",
				String.valueOf(getCurTimeSeconds())));
		// MsgType 是 news
		replyBuf.append(buildTextNode("MsgType", "news"));
		// ArticleCount 是 图文消息个数，限制为10条以内
		replyBuf.append(buildTextNode("ArticleCount", "1"));
		// Articles 是 多条图文消息信息，默认第一个item为大图,注意，如果图文数超过10，则将会无响应
		replyBuf.append("<Articles>");
		replyBuf.append("<item>");
		// Title 否 图文消息标题
		// TODO 需要获取菜单对应的数据
		replyBuf.append(buildTextNode("Title", "test"));
		// Description 否 图文消息描述
		replyBuf.append(buildTextNode("Description", "test"));
		// PicUrl 否 图片链接，支持JPG、PNG格式，较好的效果为大图360*200，小图200*200
		replyBuf.append(buildTextNode("PicUrl", "test"));
		// Url 否 点击图文消息跳转链接
		replyBuf.append(buildTextNode("Url", "test"));
		replyBuf.append("</item>");
		replyBuf.append("</Articles>");
		replyBuf.append("</xml>");

		return replyBuf.toString();
	}

	private String buildTextNode(String tag, String text) {
		// <Url><![CDATA[url]]></Url>
		return "<" + tag + "><![CDATA[" + text + "]]></" + tag + ">";
	}

	private int getCurTimeSeconds() {
		return (int) (System.currentTimeMillis() / 1000);
	}

	/**
	 * 解析微信发来的请求（XML）
	 * 
	 * @param request
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	private Map<String, String> parseXml(HttpServletRequest request)
			throws Exception {
		// 将解析结果存储在HashMap中
		Map<String, String> map = new HashMap<String, String>();
		InputStream inputStream = null;
		try {
			// 从request中取得输入流
			inputStream = request.getInputStream();
			// 读取输入流
			SAXReader reader = new SAXReader();
			Document document = reader.read(inputStream);
			// 得到xml根元素
			Element root = document.getRootElement();
			// 得到根元素的所有子节点
			List<Element> elementList = root.elements();
			// 遍历所有子节点
			for (Element e : elementList) {
				map.put(e.getName(), e.getText());
			}
			return map;

		} finally {
			// 释放资源
			IOUtils.closeQuietly(inputStream);
		}
	}

}
